package com.snow.useviewdemo.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;

import com.snow.useviewdemo.R;
import com.snow.useviewdemo.util.LogUtils;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhaoyt on 3/19/23.
 * Describe:仪表盘
 */
public class DashboardView extends View {
    public static final int SCALE_0 = 0;
    public static final int SCALE_1 = 5;
    public static final int SCALE_2 = 10;
    public static final int SCALE_3 = 50;
    public static final int SCALE_4 = 100;
    public static final int SCALE_5 = 250;
    public static final int SCALE_6 = 600;
    public static final int SCALE_7 = 750;
    public static final int SCALE_8 = 1000;

    public DashboardView(Context context) {
        this(context, null);
    }

    public DashboardView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DashboardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init();
    }

    private static final int ARC_WIDTH = 25;
    private Context mContext;
    private Paint mBgProgressPaint;
    private Paint mBgScalePaint;//刻度
    private int mRadius;
    private int viewWidth, viewHeight;
    private float roundWidth;
    private RectF ovalBg;
    private List<String> scaleList = new ArrayList<>();
    private float textSize;
    private float mCenterX, mCenterY; // 圆心坐标
    private int bgProgressColor = Color.parseColor("#29293C");
    private int max_angle = 270;
    /*************************/
    private Paint mProgressPaint;
    private Paint mShadowPaint;
    private float maxSweep = 270;
    private float mSweep = 0f;
    private RectF ovalProgress;
    private Bitmap bigPointerBmp;
    private int mPointerResId;
    private Paint mPointPaint;
    private boolean isStop;
    private int progressColor = Color.parseColor("#0285f0");
    private int shadowColor = Color.parseColor("#990285f0");
    private float mLastSweep = 0f;//最终sweep
    private float minProgressSweep = 0.1f;

    private void init() {
        /*背景初始化*/
        mBgProgressPaint = new Paint();
        mBgProgressPaint.setColor(bgProgressColor);
        mBgProgressPaint.setAntiAlias(true);
        mBgProgressPaint.setStyle(Paint.Style.STROKE);

        roundWidth = dp2px(ARC_WIDTH);
        mBgProgressPaint.setStrokeWidth(roundWidth);

        mBgScalePaint = new Paint();
        mBgScalePaint.setColor(Color.parseColor("#FFFFFF"));
        mBgScalePaint.setAntiAlias(true);
        mBgScalePaint.setStyle(Paint.Style.FILL);
        textSize = dp2px(10);
        mBgScalePaint.setTextSize(textSize);

        scaleList.clear();
        scaleList.add(String.valueOf(SCALE_0));
        scaleList.add(String.valueOf(SCALE_1));
        scaleList.add(String.valueOf(SCALE_2));
        scaleList.add(String.valueOf(SCALE_3));
        scaleList.add(String.valueOf(SCALE_4));
        scaleList.add(String.valueOf(SCALE_5));
        scaleList.add(String.valueOf(SCALE_6));
        scaleList.add(String.valueOf(SCALE_7));
        scaleList.add(String.valueOf(SCALE_8));

        /*进度条初始化*/
        mProgressPaint = new Paint();
        mProgressPaint.setColor(progressColor);
        mProgressPaint.setAntiAlias(true);
        mProgressPaint.setStyle(Paint.Style.STROKE);
        mProgressPaint.setStrokeWidth(roundWidth);

        mShadowPaint = new Paint();
        mShadowPaint.setAntiAlias(true);
        mShadowPaint.setStyle(Paint.Style.STROKE);
        mShadowPaint.setStrokeWidth(dp2px(20));

        mPointPaint = new Paint();
        mPointPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = getMeasuredWidth();
        viewHeight = getMeasuredHeight();
        mCenterX = mCenterY = getMeasuredWidth() / 2f;
        mRadius = (int) (viewWidth / 2 - roundWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBg(canvas);
        drawProgress(canvas);
    }
    /* **********绘制进度相关代码*****************/

    /**
     * 绘制进度
     *
     * @param canvas
     */
    private void drawProgress(Canvas canvas) {
        //绘制阴影
        RectF mShadowRectF = new RectF(viewWidth / 2 - mRadius + roundWidth / 2, getHeight() / 2 - mRadius + roundWidth / 2, viewWidth / 2 + mRadius - roundWidth, getHeight() / 2 + mRadius - roundWidth);
        mShadowPaint.setColor(Color.TRANSPARENT);
        mShadowPaint.setShadowLayer(roundWidth, 0, 0, shadowColor);
        canvas.drawArc(mShadowRectF, 135, mSweep, false, mShadowPaint);
        ovalProgress = new RectF(viewWidth / 2 - mRadius, getHeight() / 2 - mRadius, viewWidth / 2 + mRadius, getHeight() / 2 + mRadius);
        //画进度条
        canvas.drawArc(ovalProgress, 135, mSweep, false, mProgressPaint);//画进度条
        drawPointer(canvas);
        mSweep += minProgressSweep;
        if (mSweep <= 0) {
            mSweep = 0.1f;
        }
        if (mSweep >= maxSweep) {
            mSweep = maxSweep;
        }
        if (dashboardProgressListener != null) {
            dashboardProgressListener.currentProgressValue(getSpeedBySweep(mSweep));
        }
        //当前角度在目标角度的正负0.2之间，并且是停止的
        if (isStop) {
            minProgressSweep = (mLastSweep - mSweep) / 10f;
            if (mSweep < mLastSweep + 0.2f && mSweep > mLastSweep - 0.2f) {
                return;
            }
        }
        postInvalidateDelayed(10);
    }

    private void drawPointer(Canvas canvas) {
        Bitmap point = getPointBmp();
        if (point == null) {
            return;
        }
        canvas.save();
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
                | Paint.FILTER_BITMAP_FLAG));
        canvas.rotate(-135 + mSweep, viewWidth / 2, viewHeight / 2);
        canvas.drawBitmap(point, (viewWidth) / 2 - point.getWidth(), (viewHeight) / 2 - point.getHeight(), mPointPaint);
        canvas.restore();
    }

    /**
     * 设置指针icon
     *
     * @param mPointerResId
     */
    public void setPointerResId(int mPointerResId) {
        this.mPointerResId = mPointerResId;
    }

    private Bitmap getPointBmp() {
        if ((bigPointerBmp == null || bigPointerBmp.isRecycled()) && mPointerResId != 0) {
            bigPointerBmp = BitmapFactory.decodeResource(getResources(),
                    mPointerResId);

        } else if (bigPointerBmp == null || bigPointerBmp.isRecycled()) {
            bigPointerBmp = BitmapFactory.decodeResource(getResources(),
                    R.mipmap.dashbroard_pointer_icon);
        }
        return bigPointerBmp;
    }

    public void setProgress(float progressValue) {
        setProgress(progressValue, false);
    }

    public synchronized void setProgress(float progressValue, boolean isStop) {
        this.isStop = isStop;
        if (progressValue < 0) {
            return;
        }
        mLastSweep = getProgressSweep(progressValue);
        minProgressSweep = (mLastSweep - mSweep) / 100f;
        invalidate();
    }

    /**
     * 重置进度
     */
    public void resetProgress() {
        mSweep = 0;
        mLastSweep = 0;
        minProgressSweep = 0f;
        invalidate();
    }

    /**
     * 设置进度条颜色和阴影颜色
     *
     * @param progressColor
     * @param shadowColor
     */
    public void setProgressColor(int progressColor, int shadowColor) {
        this.progressColor = progressColor;
        this.shadowColor = shadowColor;
        if (mProgressPaint != null) {
            mProgressPaint.setColor(progressColor);
        }
    }

    /* ***********绘制背景相关代码****************************/

    /**
     * 绘制背景,背景只绘制一次
     *
     * @param canvas
     */
    private void drawBg(Canvas canvas) {
        if (scaleList == null || scaleList.isEmpty()) {
            return;
        }
        mBgProgressPaint.setColor(bgProgressColor);
        ovalBg = new RectF(getPaddingLeft() + roundWidth,
                getPaddingTop() + roundWidth,
                getMeasuredWidth() - getPaddingRight() - roundWidth,
                getMeasuredWidth() - getPaddingBottom() - roundWidth);
        //画进度条
        canvas.drawArc(ovalBg, 135, 270, false, mBgProgressPaint);//画进度条
        drawScalePoint(canvas);
        drawScaleText(canvas);
    }

    /**
     * 设置背景进度条的颜色
     *
     * @param bgProgressColor
     */
    public void setBgProgressColor(int bgProgressColor) {
        this.bgProgressColor = bgProgressColor;
        if (mBgProgressPaint != null) {
            mBgProgressPaint.setColor(bgProgressColor);
        }
    }

    /**
     * 绘制刻度point
     *
     * @param canvas
     */
    private void drawScalePoint(Canvas canvas) {
        int size = scaleList.size();
        float α;
        float[] p;
        for (int i = 0; i < size; i++) {
            α = 136 + i * ((max_angle / (size - 1) * 1.0f)) + i * 0.5f;//绘制角度有损失
            p = getCirclePoint(mRadius - (roundWidth / 2f) - dp2px(3), α);
            canvas.drawText("·", p[0], p[1], mBgScalePaint);
        }
    }

    private void drawScaleText(Canvas canvas) {
        int size = scaleList.size();
        float α;
        float[] p;
        for (int i = 0; i < size; i++) {
            String scaleText = scaleList.get(i);
            α = 135 + i * ((max_angle / (size - 1) * 1.0f)) + i * 0.9f;
            p = getCirclePoint(mRadius - (roundWidth / 2f) - dp2px(13), α);
            if (α % 360 > 135 && α % 360 < 225) {
                mBgScalePaint.setTextAlign(Paint.Align.LEFT);
            } else if ((α % 360 >= 0 && α % 360 < 45) || (α % 360 > 315 && α % 360 <= 360)) {
                mBgScalePaint.setTextAlign(Paint.Align.RIGHT);
            } else {
                mBgScalePaint.setTextAlign(Paint.Align.CENTER);
            }
            if (i == 1 || i == 2) {
                canvas.drawText(scaleText, p[0] - dp2px(2), p[1], mBgScalePaint);
            } else if (i == size - 2 || i == size - 3) {
                canvas.drawText(scaleText, p[0] + dp2px(6), p[1], mBgScalePaint);
            } else if (i == size - 1) {
                canvas.drawText(scaleText, p[0] - dp2px(2), p[1], mBgScalePaint);
            } else {
                canvas.drawText(scaleText, p[0], p[1], mBgScalePaint);
            }
        }
    }

    public float[] getCirclePoint(float radius, float angle) {
        float[] point = new float[2];
        double arcAngle = Math.PI * angle / 180.0;
        point[0] = (float) (mCenterX - dp2px(3) + Math.cos(arcAngle) * radius);
        point[1] = (float) (mCenterY + dp2px(4) + Math.sin(arcAngle) * radius);
        return point;
    }

    private float getProgressSweep(float speed) {
        float baseSweep = 270 / 8.0f;
        float resultSweep = 0;
        if (speed <= SCALE_1) {
            resultSweep = baseSweep * (speed / (SCALE_1 * 1.0f));
        } else if (speed <= SCALE_2) {
            resultSweep = baseSweep + baseSweep * (SCALE_2 - speed) / (SCALE_2 * 1.0f);
        } else if (speed <= SCALE_3) {
            resultSweep = baseSweep * 2 + baseSweep * (SCALE_3 - speed) / (SCALE_3 * 1.0f);
        } else if (speed <= SCALE_4) {
            resultSweep = baseSweep * 3 + baseSweep * (SCALE_4 - speed) / (SCALE_4 * 1.0f);
        } else if (speed <= SCALE_5) {
            resultSweep = baseSweep * 4 + baseSweep * (SCALE_5 - speed) / (SCALE_5 * 1.0f);
        } else if (speed <= SCALE_6) {
            resultSweep = baseSweep * 5 + baseSweep * (SCALE_6 - speed) / (SCALE_6 * 1.0f);
        } else if (speed <= SCALE_7) {
            resultSweep = baseSweep * 6 + baseSweep * (SCALE_7 - speed) / (SCALE_7 * 1.0f);
        } else if (speed <= SCALE_8) {
            resultSweep = baseSweep * 7 + baseSweep * (SCALE_8 - speed) / (SCALE_8 * 1.0f);
        }
        return resultSweep;
    }

    private String getSpeedBySweep(float sweep) {
        float baseSweep = 270 / 8.0f;
        float resultSpeed = 0;
        if (sweep <= baseSweep) {
            resultSpeed = (sweep / baseSweep) * (SCALE_1);
        } else if (sweep <= baseSweep * 2) {
            resultSpeed = SCALE_1 + ((sweep - baseSweep) / baseSweep) * ((SCALE_2 - SCALE_1));
        } else if (sweep <= baseSweep * 3) {
            resultSpeed = SCALE_2 + ((sweep - baseSweep * 2) / baseSweep) * ((SCALE_3 - SCALE_2));
        } else if (sweep <= baseSweep * 4) {
            resultSpeed = SCALE_3 + ((sweep - baseSweep * 3) / baseSweep) * ((SCALE_4 - SCALE_3));
        } else if (sweep <= baseSweep * 5) {
            resultSpeed = SCALE_4 + ((sweep - baseSweep * 4) / baseSweep) * ((SCALE_5 - SCALE_4));
        } else if (sweep <= baseSweep * 6) {
            resultSpeed = SCALE_5 + ((sweep - baseSweep * 5) / baseSweep) * ((SCALE_6 - SCALE_5));
        } else if (sweep <= baseSweep * 7) {
            resultSpeed = SCALE_6 + ((sweep - baseSweep * 6) / baseSweep) * ((SCALE_7 - SCALE_6));
        } else if (sweep <= baseSweep * 8) {
            resultSpeed = SCALE_7 + ((sweep - baseSweep * 7) / baseSweep) * ((SCALE_8 - SCALE_7));
        } else {
            resultSpeed = SCALE_8;
        }
        float s = resultSpeed;
        DecimalFormat df;
        if (s < 0.02) {
            s = 0f;
        }
        if (s < 1) {
            df = new DecimalFormat("0.00");
        } else if (s < 100) {
            df = new DecimalFormat("0.0");
        } else {
            df = new DecimalFormat("0");
        }
        return df.format(s);
    }

    private DashboardProgressListener dashboardProgressListener;

    /**
     * 设置进度值回调
     *
     * @param dashboardProgressListener
     */
    public void setDashboardProgressListener(DashboardProgressListener dashboardProgressListener) {
        this.dashboardProgressListener = dashboardProgressListener;
    }

    public interface DashboardProgressListener {
        void currentProgressValue(String progressValue);
    }

    private float dp2px(int dpVal) {
        return TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
    }
}
